﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using HP.Cachalote.DataModels;

namespace HP.Cachalote.Repositories.Interfaces
{
    /// <summary>
    /// An instance of IRepository against the specific DataModel type and provide standard CRUD operation only.
    /// </summary>
    /// <typeparam name="T">The specific DataModel type.</typeparam>
    public interface IRepository<T> where T : DataModelBase
    {
        /// <summary>
        /// Add new entity.
        /// </summary>
        /// <param name="entity">The new entity will be added into database.</param>
        /// <returns>The id of the new added entity.</returns>
        object Add(T entity);

        // <summary>
        /// Get entity by id. It will return null if the entity does not exist.
        /// </summary>
        /// <param name="id">The specified id.</param>
        /// <returns>The matched data.</returns>
        T Get(object id);

        /// <summary>
        /// Get entity by id. It will never return null. It will always return an entity or throw an exception.
        /// It is free to return a proxy instead. If you know that the value exist in the database, 
        /// and you don’t want to pay the extra select to have that, 
        /// but you want to get that value so we can add that reference to an object.
        /// </summary>
        /// <param name="id">The specified id.</param>
        /// <returns>The matched data.</returns>
        T Load(object id);

        /// <summary>
        /// Filter data by lambda expression.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts T and return boolean.</param>
        /// <returns>An IQueryable list of data.</returns>
        IQueryable<T> Filter(Expression<Func<T, bool>> expression);

        /// <summary>
        /// Get all data. You also can filter the data later since the returned result is a IQueryable collection.
        /// </summary>
        /// <returns>An IQueryable collection of data.</returns>
        IQueryable<T> GetAll();

        /// <summary>
        /// Get the data's count by using provided lambda expression.
        /// </summary>
        /// <param name="expression">The lambda expression that accepts T and return boolean.</param>
        /// <returns>The data's count.</returns>
        int GetRowCount(Expression<Func<T, bool>> expression);

        /// <summary>
        /// Update existing entity.
        /// </summary>
        /// <param name="entity">The entity will be updated.</param>
        void Update(T entity);

        /// <summary>
        /// Add or update entity.
        /// </summary>
        /// <param name="data">The entity will be updated if it is existing or added if it cannot be found.</param>
        void AddOrUpdate(T entity);

        /// <summary>
        /// Delete the specified entity.
        /// </summary>
        /// <param name="entity">The entity will be deleted from database.</param>
        void Delete(T entity);
    }
}
